/******************************************************************************
* MyStarNetwork Demo End Device application.
*
* It demonstrates the data transfer between end device and PAN coordinator. 
* Also the low power mode is demonstrated by switching off the tranceiver 
* using doze mode and shutting down the MCU by stop3 mode.
*
* In 802.15.4 most communications are driven by the devices in a network. They
* are typically battery powered and need to be able to control the data flow.
* in order to optimize battery life. This is done by polling for data from
* the coordinator, and transmitting data directly to the coordinator. The
* coordinator only sends data to a device when it knows it is listening, i.e. 
* when the device has requested data.
*
* This example will demonstrate indirect data transfer from the coordinator to
* the device. Data sent to the device is not transmitted immediately but put
* into a queue in the coordinators MAC. Here it resides until the device sends
* a poll request. The poll request is initiated by the network or application
* layer on the device.
*
* To test the data transfer from the coordinator to the device, both should be
* connected to a PC with an RS232 terminal at 19200bps, 8N1. When sending an
* ASCII file (send as text) from the coordinators terminal, the file will be 
* printed to the terminal connected to the device. It resembles a bidirectional
* wireless RS232 cable replacement (though, without error checking and flow 
* control in this simple example).
*
* The steps required for receiving a data packet from the coordinator are:
* 1) We should have an association to the coordinator we want to receive from.
* 2) Allocate an MLME-Poll Request message and fill in the coordinator
*    information gained during Active Scan. Send the message to the MLME.
* 3) Shut down the tranceiver and the MCU for a certain period of time.
* 4) Wake-up and wait for MCPS-Data Indication message. It may contain the data
* from the coordinator.
*
*
* (c) Copyright 2008, Freescale, Inc.  All rights reserved.
*
*
* No part of this document must be reproduced in any form - including copied,
* transcribed, printed or by any electronic means - without specific written
* permission from Freescale Semiconductor.
*
******************************************************************************/
#include "MApp.h"
#include "ApplicationConf.h"
#include "Mac_Globals.h"
#include "CommUtil.h"
#include "Sound.h"
#include "NVM_Interface.h"


uint8_t flag = 0;


/************************************************************************************
*************************************************************************************
* Private macros
*************************************************************************************
************************************************************************************/

/* Default size of data payload in MCPS-Data.request.
   The length has no real meaning since MCPS-Data.requests
   are always sent in one-size buffers big enough to hold
   a maximum length data frame. */
#define mDefaultValueOfDataLen_c               20

/* Define the message that should be sent to the coordinator
   when some key is pressed*/
#define mPredefinedMsg_c	                    "Predefined message!\n\r"
#define mPredefinedMsgLen_c	                    22

/* Define the maximum hex value that can be displayed on the LEDs */
#define mDefaultValueOfMaxDisplayVal_c          0x0F

/* Maximum number of outstanding packets */
#define mMaxPendingDataPackets_c                2

/* Define wait interval in miliseconds before another associate retry */
#define mWaitInterval_c                         ( mDefaultValueOfWaitInterval_c * 1000 )

/* Define the interval, in milliseconds, between sensor info data messages sent
 * by the End Device to the Coordinator.
 */
#define mSensorTimeInterval_c                  (2500)

#define gMessageMarkCR_c   0x0D

/* Character that triggers sending of a Device Info Message on the serial terminal interface */
#define gMessageMarkSendDevInfo    0x01

#if (gTargetMC1323xREM_d == TRUE)
#define mDeviceInfo "MC1323xREM End Device"
#elif (gTargetMC1323xRCM_d == TRUE)
#define mDeviceInfo "MC1323xRCM End Device"
#elif (gTargetMC13213NCB_d == TRUE)
#define mDeviceInfo "MC13213NCB End Device"
#elif (gTargetMC13213SRB_d == TRUE)
#define mDeviceInfo "MC13213SRB End Device"
#elif (gTargetQE128EVB_d == TRUE)
#define mDeviceInfo "MC1320xEVB End Device"
#elif (gTargetMC1323xUSBR2_d == TRUE)
#define mDeviceInfo "MC1323xUSBR2 End Device"
#else
#define mDeviceInfo "Custom HCS08 End Device"
#endif


/************************************************************************************
*************************************************************************************
* Private prototypes
*************************************************************************************
************************************************************************************/
static void    App_CommRxCallBack(void);
static void    App_CommRxCallBackEnd(void);
static uint8_t App_StartScan(uint8_t scanType);
static uint8_t App_HandleScanActiveConfirm(nwkMessage_t *pMsg);
static uint8_t App_WaitMsg(nwkMessage_t *pMsg, uint8_t msgType);
static uint8_t App_SendAssociateRequest(void);
static uint8_t App_HandleAssociateConfirm(nwkMessage_t *pMsg);
static uint8_t App_HandleMlmeInput(nwkMessage_t *pMsg);
static bool_t  App_Idle(void);
static void    App_HandleMcpsInput(mcpsToNwkMessage_t *pMsgIn);
static void    App_SendPredefinedMessage(void);
static void    App_SendSensorStatus(void);
static void    App_ReceiveData(void);
static void    App_HandleMessage(mcpsToNwkMessage_t *pMsgIn);
static void    App_UpdateLEDs(uint8_t val);
static void    App_IntervalTimeoutHandler(uint8_t timerID);
static void    App_TransmitData(uint8_t * pData, uint8_t length);
static void    App_SensorIntervalTimeoutHandler(uint8_t timerID);
static void    App_PollIntervalTimeoutHandler(uint8_t timerID);
#if (gMC1323xMatrixKBD_d == TRUE)
static void    App_HandleKeys(uint8_t events, uint8_t pressedKey);
#else
static void    App_HandleKeys(key_event_t events);
#endif //gMC1323xMatrixKBD_d

/************************************************************************************
*************************************************************************************
* Private type definitions
*************************************************************************************
************************************************************************************/


/************************************************************************************
*************************************************************************************
* Private memory declarations
*************************************************************************************
************************************************************************************/

/* Information about the PAN we are part of */
static panDescriptor_t mCoordInfo;

/* This is the short address assigned by the PAN coordinator
   during association. */
static uint8_t maAddress[2];

/* Data request packet for sending serial terminal interface input to the coordinator */
static nwkToMcpsMessage_t *mpPacket = NULL;

/* The MSDU handle is a unique data packet identifier */
static uint8_t mMsduHandle = 0;

/* Number of pending data packets */
static uint8_t mcPendingPackets = 0;

/* Signals that an MLME-Poll request is pending, and that we should wait
   for the MLME-Poll confirm message before sending the next poll request. 
   At init we allow sending a poll request.
*/
static bool_t mWaitPollConfirm = FALSE;

/* Buffer for a message to be sent to coodinator when user presses a key */
static uint8_t maGeneralMsg[mPredefinedMsgLen_c] = mPredefinedMsg_c;  

/* Flag to stop pooling coordintator for data. This way we ensure that idle
   task gets executed and device can enter low power mode.
*/
static bool_t mStopPolling = FALSE;


/* Application input queues */
static anchor_t mMlmeNwkInputQueue;
static anchor_t mMcpsNwkInputQueue;
static tmrTimerID_t mSoftTimerId_c = gTmrInvalidTimerID_c;
static tmrTimerID_t mSensorTimerId_c = gTmrInvalidTimerID_c;
static tmrTimerID_t mPollIntervalTimerId_c = gTmrInvalidTimerID_c;

/************************************************************************************
*************************************************************************************
* Public memory declarations
*************************************************************************************
************************************************************************************/

/* The current state of the applications state machine */
uint8_t gState;

/* This data set contains application variables to be preserved across resets */
NvDataItemDescription_t const gaNvAppDataSet[] = {
  {NULL, 0}       /* Required end-of-table marker. */
};

/************************************************************************************
*************************************************************************************
* Public functions
*************************************************************************************
************************************************************************************/

void DeepSleepWakeupStackProc(void);


/*****************************************************************************
* Initialization function for the App Task. This is called during
* initialization and should contain any application specific initialization
* (ie. hardware initialization/setup, table initialization, power up
* notificaiton.
*
* Interface assumptions: None
*
* Return value: None
*
*****************************************************************************/
void MApp_init(void)
{   

  /* The initial application state */
  gState = stateInit;    

  /* Initialize the MAC 802.15.4 extended address */
  Init_MacExtendedAddress();


  mSoftTimerId_c = TMR_AllocateTimer();

  mPollIntervalTimerId_c = TMR_AllocateTimer();
  
  /* Allocate sensor data sending timer */
  mSensorTimerId_c = TMR_AllocateTimer();
  
  /* Register keyboard callback function */
  KBD_Init(App_HandleKeys);
  /* Initialize SPI Module */
  SPI_Init();  
  /* Initialize LCD Module */
  LCD_Init();
  /* initialize LED Module */
  LED_Init();
  
  /* Initialize the Low Power Management module */
  PWRLib_Init();
  /* Initialize the serial terminal interface so that we can print out status messages */
  Comm_SetBaud(gUartDefaultBaud_c);
  Comm_SetRxCallBack(App_CommRxCallBack);
  Comm_SetRxCallBack(App_CommRxCallBackEnd);

  /* initialize buzzer (NCB, SRB only) */  
  BuzzerInit();  

  /* Prepare input queues.*/
  MSG_InitQueue(&mMlmeNwkInputQueue); 
  MSG_InitQueue(&mMcpsNwkInputQueue); 
    
  /* Enable MCU interrupts */
  IrqControlLib_EnableAllIrqs();
  
  /*signal app ready*/  
  Led1Flashing();
  Led2Flashing();
  Led3Flashing();
  Led4Flashing();
    
  CommUtil_Print("\n\rPress any switch on board to start running the application.\n\r", gAllowToBlock_d);  
  LCD_ClearDisplay();  
  LCD_WriteString(1,"Press any key");
  LCD_WriteString(2,"to start.");  
}


/*****************************************************************************
* The AppTask(event_t events) function is the applicantion main loop and 
* will process any incoming event. Events include timers, messages and any 
* other user defined events.
*
* Interface assumptions:
*     None
*
* Return value: 
*     None
*****************************************************************************/
void AppTask(event_t events) 
{ 
  /* Pointer for storing the messages from MLME, MCPS, and ASP. */
  void *pMsgIn;
  /* Stores the status code returned by some functions. */
  uint8_t rc;  
  static uint8_t maCommDataBuffer[mDefaultValueOfDataLen_c] = {0};	
  static uint8_t mCounter = 0;
  pMsgIn = NULL;


  
  /* Dequeue the MLME message */
  if (events & gAppEvtMessageFromMLME_c)
  {
    /* Get the message from MLME */
    pMsgIn = MSG_DeQueue(&mMlmeNwkInputQueue);
    
    /* Any time a beacon might arrive. Always handle the beacon frame first */
    if (pMsgIn)
    {               
      rc = App_WaitMsg(pMsgIn, gNwkBeaconNotifyInd_c);
      if(rc == errorNoError)
      {
        /* ALWAYS free the beacon frame contained in the beacon notify indication.*/
        /* ALSO the application can use the beacon payload.*/
        MSG_Free(((nwkMessage_t *)pMsgIn)->msgData.beaconNotifyInd.pBufferRoot);
        CommUtil_Print("Received an MLME-Beacon Notify Indication\n\r", gAllowToBlock_d);
      }
    }
  }
  switch(gState)
  {    
    case stateInit:       
      /* Goto Energy Detection state. */
      gState = stateScanActiveStart;
      TS_SendEvent(gAppTaskID_c, gAppEvtDummyEvent_c);  
          

      /* Print a welcome message to the serial terminal interface */
      CommUtil_Print("\n\rMyStarNetworkDemo-EndDevice application is initialized and ready.\n\r", gAllowToBlock_d);
      break;    

    case stateScanActiveStart:
      /* Start the Active scan, and goto wait for confirm state. */
      CommUtil_Print("Start scanning for a PAN coordinator.\n\r", gAllowToBlock_d);
      LCD_ClearDisplay();
      LCD_WriteString(1,"Start scanning");
      LCD_WriteString(2,"for coordinator");		  
      
      rc = App_StartScan(gScanModeActive_c);
      if(rc == errorNoError)
      {
        gState = stateScanActiveWaitConfirm;
      }
      break;

    case stateScanActiveWaitConfirm:
      /* Stay in this state until the Scan confirm message arrives, and then goto
      the associate state or do a rescan in case of invalid short address. 
      */

      /* ALWAYS free the beacon frame contained in the beacon notify indication.*/

      if (events & gAppEvtMessageFromMLME_c)
      {
        if (pMsgIn)
        {
          /* Handle the Scan Confirm message. */
          rc = App_WaitMsg(pMsgIn, gNwkScanCnf_c);
          if(rc == errorNoError)
          {        
            rc = App_HandleScanActiveConfirm(pMsgIn);
            if(rc == errorNoError)
            { 
              CommUtil_Print("Found a coordinator with the following properties:.\n\r", gAllowToBlock_d);
              CommUtil_Print("----------------------------------------------------.", gAllowToBlock_d);
              CommUtil_Print("\n\rAddress...........0x", gAllowToBlock_d); CommUtil_PrintHex(mCoordInfo.coordAddress, mCoordInfo.coordAddrMode == gAddrModeShort_c ? 2 : 8, 0);CommUtil_Print(".\n\r", gAllowToBlock_d);
              CommUtil_Print("\n\rPAN ID............0x", gAllowToBlock_d); CommUtil_PrintHex(mCoordInfo.coordPanId, 2, 0);CommUtil_Print(".\n\r", gAllowToBlock_d);
              CommUtil_Print("\n\rLogical Channel...0x", gAllowToBlock_d); CommUtil_PrintHex(&mCoordInfo.logicalChannel, 1, 0);CommUtil_Print(".\n\r", gAllowToBlock_d);
              CommUtil_Print("\n\rBeacon Spec.......0x", gAllowToBlock_d); CommUtil_PrintHex(mCoordInfo.superFrameSpec, 2, 0);CommUtil_Print(".\n\r", gAllowToBlock_d);
              CommUtil_Print("\n\rLink Quality......0x", gAllowToBlock_d); CommUtil_PrintHex(&mCoordInfo.linkQuality, 1, 0);CommUtil_Print(".\n\r", gAllowToBlock_d);
              CommUtil_Print("\n\r\n\r", gAllowToBlock_d);

              gState = stateAssociate;
              TS_SendEvent(gAppTaskID_c, gAppEvtDummyEvent_c);
            }
            else
            {                   
              /* Restart scanning */
              CommUtil_Print("Scan did not find a suitable coordinator.\n\r", gAllowToBlock_d);
              /* Print a message on the LCD */
              LCD_ClearDisplay();
              LCD_WriteString(1,"No coordinator");
              LCD_WriteString(2,"found");					  
              TMR_StartSingleShotTimer(mSoftTimerId_c, mWaitInterval_c, App_IntervalTimeoutHandler);
              gState = stateWaitInterval;
            }
          }
        }
      }
    break;

    case stateWaitInterval:
      if (events & gAppEvtStartWait_c)
      {        
        gState = stateScanActiveStart;
        TS_SendEvent(gAppTaskID_c, gAppEvtDummyEvent_c);                      
      }
      break;

    case stateAssociate:
      /* Associate to the PAN coordinator */
      CommUtil_Print("Associating to PAN coordinator on channel 0x", gAllowToBlock_d);
      CommUtil_PrintHex(&(mCoordInfo.logicalChannel), 1, 0);
      CommUtil_Print(".\n\r", gAllowToBlock_d);
      LCD_ClearDisplay();
      LCD_WriteString(1,"Associating to ");
      LCD_WriteString(2,"PAN coordinator");		  
      rc = App_SendAssociateRequest();
      if(rc == errorNoError)
      {        
        gState = stateAssociateWaitConfirm;
      }
    break; 

    case stateAssociateWaitConfirm:
      /* Stay in this state until the Associate confirm message
      arrives, and then goto the Listen state. */
      if (events & gAppEvtMessageFromMLME_c)
      {
        if (pMsgIn)
        {                    
          rc = App_WaitMsg(pMsgIn, gNwkAssociateCnf_c);
          if(rc == errorNoError)
          {        
            /* Check for coordinator at full capacity error */
            if (App_HandleAssociateConfirm(pMsgIn) == gSuccess_c)
            {        
                  gState = stateListen;
                  CommUtil_Print("Device successfully associated.\n\r", gAllowToBlock_d);
                  CommUtil_Print("We were assigned the short address 0x", gAllowToBlock_d);
                  CommUtil_PrintHex(maAddress, 2, 0);
                  CommUtil_Print(".\n\r\n\rEnd Device ready to send and receive data over the serial terminal interface.\n\r", gAllowToBlock_d);
              
                  /* Print a message on the LCD */
		          LCD_ClearDisplay();
		          LCD_WriteString(1,"End device ready");
		          LCD_WriteString(2,"to send&receive ");
		          TS_SendEvent(gAppTaskID_c, gAppEvtDummyEvent_c);
		          
		          /* Start sensor data sending interval timer. */
		          TMR_StartIntervalTimer( mSensorTimerId_c, mSensorTimeInterval_c, App_SensorIntervalTimeoutHandler);
		          
		          /* Start poll interval timer. */  
                  TMR_StartIntervalTimer(mPollIntervalTimerId_c, mDefaultValueOfPollInterval_c, App_PollIntervalTimeoutHandler);
			      
    		    }
            else
            {        
              /* Restart scanning */
              CommUtil_Print("No valid short address. Retry scan.\n\r", gAllowToBlock_d);
              /* Print a message on the LCD */
		          LCD_ClearDisplay();
		          LCD_WriteString(1,"No valid address.");
		          LCD_WriteString(2,"  Retry scan.");	 			  
              
              TMR_StartSingleShotTimer(mSoftTimerId_c, mWaitInterval_c, App_IntervalTimeoutHandler);
              gState = stateWaitInterval;
            }
          }
        }        
      }
      break; 
    
    case stateListen:
      /* Stay in this state forever. Handles poll confirm etc. */
      if (events & gAppEvtMessageFromMLME_c)
      {  
        if (pMsgIn)
        {  
          /* Process it */
          rc = App_HandleMlmeInput(pMsgIn);
        }

      }
      if (events & gAppEvtRxFromComm_c)
           {      
     		(void)Comm_GetByteFromRxBuffer(&maCommDataBuffer[mCounter]);
     		if (gMessageMarkSendDevInfo == maCommDataBuffer[mCounter]){
     			//App_CommSendDeviceInfo();
     		}
     		else if((mCounter == (mDefaultValueOfDataLen_c-1))||(maCommDataBuffer[mCounter] == gMessageMarkCR_c)){
     		  App_TransmitData(maCommDataBuffer, mCounter);
     		  mCounter = 0;
     		}else{
     		  mCounter++;
     		}
           }     
      break;
  } /* end switch */
  
  /* Free Mlme Messages */
  if (pMsgIn)
  {
    /* Messages must always be freed. */ 
    MSG_Free(pMsgIn);
  }
  
  /* Handle MCPS confirms and transmit data from serial terminal interface */
  if (events & gAppEvtMessageFromMCPS_c)
  {      
    /* Get the message from MCPS */
    pMsgIn = MSG_DeQueue(&mMcpsNwkInputQueue);
    if (pMsgIn)
    {              
      /* Process it */
      App_HandleMcpsInput(pMsgIn);
      /* Messages from the MCPS must always be freed. */
      MSG_Free(pMsgIn);
    }
  }
  
if( gState == stateListen) 
{
  
   if(events & gAppEvtSendPollReq_c)
   {	
  /* Poll coordinator for data. */	    
	    if (!mStopPolling)
	    {
	   
	      App_ReceiveData();
	      
#if (gLpmIncluded_d == 1)	                     	        
	      /* Stop polling coordintor in order to ensure that idle task 
	         gets executed. */
	      mStopPolling = TRUE;	      
#endif	      
	    }
   }

#if (gLpmIncluded_d == 1)	                     	        
       /* Check and if possible allow device to enter sleep mode */
      if(App_Idle() == TRUE)         
      {

        /* Allow device to enter sleep mode. The device will enter
           in low power first time the idle task gets called.
        */
        flag = 0;
        PWR_AllowDeviceToSleep(); 
        mStopPolling = FALSE;

      }else
      {
         TS_SendEvent(gAppTaskID_c, gAppEvtDummyEvent_c);
      }
 
#endif      

      if (events & gAppEvtSendMessage_c)
      {
        App_SendPredefinedMessage();                         
      }
      
      if (events & gAppEvtSendSensorData_c)
      {
    	App_SendSensorStatus();
      }
 
}

  /* Check for pending messages in the Queue */ 
  if(MSG_Pending(&mMcpsNwkInputQueue))
    TS_SendEvent(gAppTaskID_c, gAppEvtMessageFromMCPS_c);
  if(MSG_Pending(&mMlmeNwkInputQueue))
    TS_SendEvent(gAppTaskID_c, gAppEvtMessageFromMLME_c);  
}

/*****************************************************************************
* App_CommRxCallBack
*
* This callback is triggered when a new byte is received over the serial terminal interface
*
*****************************************************************************/
static void App_CommRxCallBack(void) 
{
  uint8_t pressedKey;
  (void)Comm_GetByteFromRxBuffer(&pressedKey);
  if(gMessageMarkSendDevInfo == pressedKey){
	/* Print device info */
	CommUtil_Print((uint8_t*) mDeviceInfo, gAllowToBlock_d);
	}
}

static void App_CommRxCallBackEnd(void) //ESTA FUNCION ES EL EVENTO QUE RESPONDE AL ENTER DEL TECLADO//
{
  uint8_t pressedKeyEnd;
  if(stateListen == gState){
     TS_SendEvent(gAppTaskID_c, gAppEvtRxFromComm_c);
  }else{
	 (void)Comm_GetByteFromRxBuffer(&pressedKeyEnd);
	 if(gMessageMarkSendDevInfo == pressedKeyEnd){
		 //App_CommSendDeviceInfo();
	 }
  }
}
/******************************************************************************
* The App_StartScan(scanType) function will start the scan process of the
* specified type in the MAC. This is accomplished by allocating a MAC message,
* which is then assigned the desired scan parameters and sent to the MLME
* service access point.
*
* The function may return either of the following values:
*   errorNoError:          The Scan message was sent successfully.
*   errorInvalidParameter: The MLME service access point rejected the
*                          message due to an invalid parameter.
*   errorAllocFailed:      A message buffer could not be allocated.
*
******************************************************************************/
static uint8_t App_StartScan(uint8_t scanType)
{
  mlmeMessage_t *pMsg;
  mlmeScanReq_t *pScanReq;

  CommUtil_Print("Sending the MLME-Scan Request message to the MAC... ", gAllowToBlock_d);

  /* Allocate a message for the MLME (We should check for NULL). */
  pMsg = MSG_AllocType(mlmeMessage_t);
  if(pMsg != NULL)
  {
    /* This is a MLME-SCAN.req command */
    pMsg->msgType = gMlmeScanReq_c;
    /* Create the Scan request message data. */
    pScanReq = &pMsg->msgData.scanReq;
    /* gScanModeED_c, gScanModeActive_c, gScanModePassive_c, or gScanModeOrphan_c */
    pScanReq->scanType = scanType;
    /* ChannelsToScan & 0xFF - LSB, always 0x00 */
    pScanReq->scanChannels[0] = (uint8_t)((mDefaultValueOfChannel_c)     & 0xFF);
    /* ChannelsToScan>>8 & 0xFF  */
    pScanReq->scanChannels[1] = (uint8_t)((mDefaultValueOfChannel_c>>8)  & 0xFF);
    /* ChannelsToScan>>16 & 0xFF  */
    pScanReq->scanChannels[2] = (uint8_t)((mDefaultValueOfChannel_c>>16) & 0xFF);
    /* ChannelsToScan>>24 & 0xFF - MSB */
    pScanReq->scanChannels[3] = (uint8_t)((mDefaultValueOfChannel_c>>24) & 0xFF);
    /* Duration per channel 0-14 (dc). T[sec] = (16*960*((2^dc)+1))/1000000.
    A scan duration of 5 on 16 channels approximately takes 8 secs. */
    pScanReq->scanDuration = 5;
#ifdef gMAC2006_d
	pScanReq->securityLevel = 0; //No security is used
#endif //gMAC2006_d	

    /* Send the Scan request to the MLME. */
    if(MSG_Send(NWK_MLME, pMsg) == gSuccess_c)
    {
      CommUtil_Print("Done.\n\r", gAllowToBlock_d);  
      return errorNoError;
    }																	 
    else
    {
      CommUtil_Print("Invalid parameter.\n\r", gAllowToBlock_d);
      return errorInvalidParameter;
    }
  }
  else
  {
    /* Allocation of a message buffer failed. */
    CommUtil_Print("Message allocation failed.\n\r", gAllowToBlock_d);
    return errorAllocFailed;
  }
}

/******************************************************************************
* The App_HandleScanActiveConfirm(nwkMessage_t *pMsg) function will handle the
* Active Scan confirm message received from the MLME when the Active scan has
* completed. The message contains a list of PAN descriptors. Based on link
* quality inforamtion in the pan descriptors the nearest coordinator is chosen.
* The corresponding pan descriptor is stored in the global variable mCoordInfo. 
*
* The function may return either of the following values:
*   errorNoError:       A suitable pan descriptor was found.
*   errorNoScanResults: No scan results were present in the confirm message.
*
******************************************************************************/
static uint8_t App_HandleScanActiveConfirm(nwkMessage_t *pMsg)
{
  void    *pBlock;
  uint8_t panDescListSize = pMsg->msgData.scanCnf.resultListSize;
  uint8_t rc = errorNoScanResults;
  uint8_t j;
  uint8_t bestLinkQuality = 0;  
  panDescriptorBlock_t *pDescBlock = pMsg->msgData.scanCnf.resList.pPanDescriptorBlocks;  
  panDescriptor_t *pPanDesc;     
  
 
  /* Check if the scan resulted in any coordinator responses. */  
  
  if (panDescListSize > 0)
  {    
    /* Check all PAN descriptors. */
    while (NULL != pDescBlock)
    {
      for (j = 0; j < pDescBlock->descriptorCount; j++)
      {            
        pPanDesc = &pDescBlock->descriptorList[j];

        /* Only attempt to associate if the coordinator
           accepts associations and is non-beacon. */
        if( ( pPanDesc->superFrameSpec[1] & gSuperFrameSpecMsbAssocPermit_c) && 
            ((pPanDesc->superFrameSpec[0] & gSuperFrameSpecLsbBO_c) == 0x0F) )
        {        
          
          /* Find the nearest coordinator using the link quality measure. */
          if(pPanDesc->linkQuality > bestLinkQuality)
          {
            /* Save the information of the coordinator candidate. If we
               find a better candiate, the information will be replaced. */
            FLib_MemCpy(&mCoordInfo, pPanDesc, sizeof(panDescriptor_t));
            bestLinkQuality = pPanDesc->linkQuality;
            rc = errorNoError;
          }
        }      
      }
      
      /* Free current block */
      pBlock = pDescBlock;
      pDescBlock = pDescBlock->pNext;              
      MSG_Free(pBlock);
    }
  }
  
  if (pDescBlock)
      MSG_Free(pDescBlock);
  
  return rc;
}

/******************************************************************************
* The App_SendAssociateRequest(void) will create an Associate Request message
* and send it to the coordinator it wishes to associate to. The function uses
* information gained about the coordinator during the scan procedure.
*
* The function may return either of the following values:
*   errorNoError:          The Associate Request message was sent successfully.
*   errorInvalidParameter: The MLME service access point rejected the
*                          message due to an invalid parameter.
*   errorAllocFailed:      A message buffer could not be allocated.
*
******************************************************************************/
static uint8_t App_SendAssociateRequest(void)
{
  mlmeMessage_t *pMsg;
  mlmeAssociateReq_t *pAssocReq;

  CommUtil_Print("Sending the MLME-Associate Request message to the MAC ", gAllowToBlock_d);

  /* Allocate a message for the MLME message. */
  pMsg = MSG_AllocType(mlmeMessage_t);
  if(pMsg != NULL)
  {
    /* This is a MLME-ASSOCIATE.req command. */
    pMsg->msgType = gMlmeAssociateReq_c;

    /* Create the Associate request message data. */
    pAssocReq = &pMsg->msgData.associateReq;

    /* Use the coordinator info we got from the Active Scan. */
    memcpy(pAssocReq->coordAddress, mCoordInfo.coordAddress, 8);
    memcpy(pAssocReq->coordPanId,   mCoordInfo.coordPanId, 2);
    pAssocReq->coordAddrMode      = mCoordInfo.coordAddrMode;
    pAssocReq->logicalChannel     = mCoordInfo.logicalChannel;
#ifndef gMAC2006_d	
    pAssocReq->securityEnable     = FALSE;
#else
	pAssocReq->securityLevel = 0;
#endif //gMAC2006_d	
    /* We want the coordinator to assign a short address to us. */
    pAssocReq->capabilityInfo     = gCapInfoAllocAddr_c;

    /* Send the Associate Request to the MLME. */
    if(MSG_Send(NWK_MLME, pMsg) == gSuccess_c)
    {
      CommUtil_Print("Done.\n\r", gAllowToBlock_d);
      return errorNoError;
    }
    else
    {
      /* One or more parameters in the message were invalid. */
      CommUtil_Print("Invalid parameter.\n\r", gAllowToBlock_d);
      return errorInvalidParameter;
    }
  }
  else
  {
    /* Allocation of a message buffer failed. */
    CommUtil_Print("Message allocation failed.\n\r", gAllowToBlock_d);
    return errorAllocFailed;
  }
}


/******************************************************************************
* The App_HandleAssociateConfirm(nwkMessage_t *pMsg) function will handle the
* Associate confirm message received from the MLME when the Association
* procedure has completed. The message contains the short address that the
* coordinator has assigned to us. The address and address mode are saved in
* global variables. They will be used in the next demo application when sending
* data .
*
* The function may return either of the following values:
*   gSuccess_c:          Correct short address 
*   gPanAccessDenied_c:  Invalid short address
*
******************************************************************************/
static uint8_t App_HandleAssociateConfirm(nwkMessage_t *pMsg)
{
  if(pMsg->msgData.associateCnf.status == gSuccess_c)
  {
    memcpy(maAddress, pMsg->msgData.associateCnf.assocShortAddress, 2);
    return gSuccess_c;        
  }
  else
  {
    /* No valid short address. */
    return gPanAccessDenied_c;  
  }  
}


/******************************************************************************
* The App_HandleMlmeInput(nwkMessage_t *pMsg) function will handle various
* messages from the MLME, e.g. poll confirm.
*
* The function may return either of the following values:
*   errorNoError:   The message was processed.
*   errorNoMessage: The message pointer is NULL.
*
******************************************************************************/
static uint8_t App_HandleMlmeInput(nwkMessage_t *pMsg)
{
  if(pMsg == NULL)
  {    
    return errorNoMessage;
  }

  /* Handle the incoming message. The type determines the sort of processing.*/
  switch(pMsg->msgType)
  {
    case gNwkPollCnf_c:
      if(pMsg->msgData.pollCnf.status != gSuccess_c)
      {      
        /* If we get to this point, then no data was available, and we
        allow a new poll request. Otherwise, we wait for the data
        indication before allowing the next poll request. */

        
        mWaitPollConfirm = FALSE;
      }
      break;
  }
  return errorNoError;
}


/******************************************************************************
* The App_HandleMcpsInput(mcpsToNwkMessage_t *pMsgIn) function will handle 
* messages from the MCPS, e.g. Data Confirm, and Data Indication.
*
******************************************************************************/
static void App_HandleMcpsInput(mcpsToNwkMessage_t *pMsgIn)
{
  switch(pMsgIn->msgType)
  {
    /* The MCPS-Data confirm is sent by the MAC to the network 
    or application layer when data has been sent. */
    case gMcpsDataCnf_c:
      if(mcPendingPackets)
      {        
        mcPendingPackets--;
      }
      break;

    case gMcpsDataInd_c:
      /* Handle message */
      App_HandleMessage(pMsgIn);

      /* Allow another MLME-Poll request. */
      mWaitPollConfirm = FALSE;
      break;
  }
}


/******************************************************************************
* The App_HandleMessage(mcpsToNwkMessage_t *pMsgIn) function will handle a 
* data indication message from the MCPS.If it is a network activity message,
* the value received from the coordinator is displayed on the LEDs . If it is
* a data packet , we send it to the serial terminal interface.
*
******************************************************************************/
static void App_HandleMessage(mcpsToNwkMessage_t *pMsgIn)
{
  uint8_t val = *(pMsgIn->msgData.dataInd.pMsdu);
  if (( pMsgIn->msgData.dataInd.msduLength == 1 ) &&
      ( val <= mDefaultValueOfMaxDisplayVal_c ))
  {    
    App_UpdateLEDs(val);
  }
  else
  {
    uint8_t hex = pMsgIn->msgData.dataInd.mpduLinkQuality;
    CommUtil_Print("\n\rPAN Coordinator(0x", gAllowToBlock_d);
    CommUtil_PrintHex(&hex,1,0);
    CommUtil_Print("):", gAllowToBlock_d);
    CommUtil_Tx(pMsgIn->msgData.dataInd.pMsdu, pMsgIn->msgData.dataInd.msduLength);
    CommUtil_Print("\n\r", gAllowToBlock_d);
  }
}


/******************************************************************************
* The App_WaitMsg(nwkMessage_t *pMsg, uint8_t msgType) function does not, as
* the name implies, wait for a message, thus blocking the execution of the
* state machine. Instead the function analyzes the supplied message to 
* determine whether or not the message is of the expected type.
*
* The function may return either of the following values:
*   errorNoError: The message was of the expected type.
*   errorNoMessage: The message pointer is NULL.
*   errorWrongConfirm: The message is not of the expected type.
*
******************************************************************************/
static uint8_t App_WaitMsg(nwkMessage_t *pMsg, uint8_t msgType)
{
  /* Do we have a message? If not, the exit with error code */
  if(pMsg == NULL)
  {    
    return errorNoMessage;
  }

  /* Is it the expected message type? If not then exit with error code */
  if(pMsg->msgType != msgType)
  {    
    return errorWrongConfirm;
  }

  /* Found the expected message. Return with success code */
  return errorNoError;
}


/******************************************************************************
* The App_SendPredefinedMessage() function will perform  data transmissions of
* a predefined message to show some kind of a network activity. Data could also 
* come from other sources such as sensors etc. This is completely determined by
* the application. The constant mMaxPendingDataPackets_c determine the maximum
* number of packets pending for transmission in the MAC. A global variable
* is incremented each time a data packet is sent to the MCPS, and decremented
* when the corresponding MCPS-Data Confirm message is received. If the counter
* reaches the defined maximum no more data buffers are allocated until the
* counter is decreased below the maximum number of pending packets.
*
* The function uses the coordinator information gained during the Active Scan,
* and the short address assigned to us by coordinator, for building an MCPS-
* Data Request message. The message is sent to the MCPS service access point
* in the MAC.
*
******************************************************************************/
static void App_SendPredefinedMessage(void)
{   
  
  mpPacket = NULL;
  
  /* Data request packet for sending serial terminal interface input to the coordinator */

  if( (mcPendingPackets < mMaxPendingDataPackets_c) && (mpPacket == NULL) )
  {
    /* If the maximum number of pending data buffes is below maximum limit 
    and we do not have a data buffer already then allocate one. */    
    mpPacket = MSG_Alloc(gMaxRxTxDataLength_c);
  }

  if(mpPacket != NULL)
  {  
    
    mpPacket->msgData.dataReq.pMsdu = (uint8_t*)(&(mpPacket->msgData.dataReq.pMsdu)) + sizeof(uint8_t*);
    FLib_MemCpy(mpPacket->msgData.dataReq.pMsdu, (uint8_t*) maGeneralMsg, mPredefinedMsgLen_c);
     
       
    /* Data was available in the serial terminal interface receive buffer. Now create an
    MCPS-Data Request message containing the serial terminal interface data. */
    mpPacket->msgType = gMcpsDataReq_c;
    /* Create the header using coordinator information gained during 
    the scan procedure. Also use the short address we were assigned
    by the coordinator during association. */
    
    memcpy(mpPacket->msgData.dataReq.dstAddr, mCoordInfo.coordAddress, 8);               
    memcpy(mpPacket->msgData.dataReq.srcAddr, maAddress, 2);
    memcpy(mpPacket->msgData.dataReq.dstPanId, mCoordInfo.coordPanId, 2);           
    memcpy(mpPacket->msgData.dataReq.srcPanId, mCoordInfo.coordPanId, 2);
    mpPacket->msgData.dataReq.dstAddrMode = mCoordInfo.coordAddrMode;
    mpPacket->msgData.dataReq.srcAddrMode = gAddrModeShort_c;
    mpPacket->msgData.dataReq.msduLength = mPredefinedMsgLen_c;

    /* Request MAC level acknowledgement of the data packet */
    mpPacket->msgData.dataReq.txOptions = gTxOptsAck_c;
    /* Give the data packet a handle. The handle is
    returned in the MCPS-Data Confirm message. */
    mpPacket->msgData.dataReq.msduHandle = mMsduHandle++;
#ifdef gMAC2006_d
	mpPacket->msgData.dataReq.securityLevel = 0;
#endif //gMAC2006_d	

    /* Send the Data Request to the MCPS */
    NR MSG_Send(NWK_MCPS, mpPacket);
    
    /* Prepare for another data buffer */
    mcPendingPackets++;
  }
}

/******************************************************************************
* The App_SendSensorStatus() function will perform  data transmissions of
* sensor data to the coordinator. It works exactly like the
* App_SendPredefinedMessage() function above. See it's description for details.
******************************************************************************/
static void App_SendSensorStatus(void)
{   
  //Dummy ON/OFF button status
  static uint8_t dummyToggleStatus = 0x00;
  // Dummy control info: suggests to the Coordinator that the End Device
  // will send info about: ON/OFF button, temperature sensor, Accelerometer and
  // pressure sensor
  static uint8_t dummyControlInfo = 0x0F;
  // Dummy accelerometer data
  static int16_t dummyAccelData[3] = {76, 84, 67};
  // Dummy pressure data
  static int16_t dummyPressure = 14;
  // Dummy temperature data
  static int8_t  dummyTemperature = 23;
  // Dummy battery level
  static int8_t  dummyBatteryLevel = 31;
  
  mpPacket = NULL;
  
  // Pseudo randomize dummy sensor data
  //dummyToggleStatus
  dummyToggleStatus = (dummyTemperature & 0x02) >> 1;
  //dummyAccelData
  dummyAccelData[0] += 3;
  if (dummyAccelData[0] >= 85)
  {
	  dummyAccelData[0] -= 13;
  }
  dummyAccelData[1] += 5;
  if (dummyAccelData[1] >= 81)
  {
      dummyAccelData[1] -= 17;
  }
  dummyAccelData[2] += 3;
  if (dummyAccelData[2] >= 90)
  {
      dummyAccelData[2] -= 11;
  }
  
  //dummyPressure
  dummyPressure += 2;
  if (dummyPressure >= 24)
  {
	  dummyPressure -= 7;
  }
  
  //dummyTemperature
  dummyTemperature += 1;
  if (dummyTemperature >= 29)
  {
      dummyTemperature -= 6;
  }
  
  //dummyBatteryLevel
  dummyBatteryLevel += 1;
  if (dummyBatteryLevel >= 32)
  {
	  dummyBatteryLevel -= 4;
  }
  
  if( (mcPendingPackets < mMaxPendingDataPackets_c) && (mpPacket == NULL) )
  {
    /* If the maximum number of pending data buffes is below maximum limit 
    and we do not have a data buffer already then allocate one. */    
    mpPacket = MSG_Alloc(gMaxRxTxDataLength_c);
  }

  if(mpPacket != NULL)
  {       
    /* Data was available in the serial terminal interface receive buffer. Now create an
    MCPS-Data Request message containing the serial terminal interface data. */
    mpPacket->msgType = gMcpsDataReq_c;
    /* Create the header using coordinator information gained during 
    the scan procedure. Also use the short address we were assigned
    by the coordinator during association. */
    mpPacket->msgData.dataReq.pMsdu = (uint8_t*)(&(mpPacket->msgData.dataReq.pMsdu)) + sizeof(uint8_t*);
    
    FLib_MemCpy(mpPacket->msgData.dataReq.dstAddr, mCoordInfo.coordAddress, 8);               
    FLib_MemCpy(mpPacket->msgData.dataReq.srcAddr, maAddress, 2);
    FLib_MemCpy(mpPacket->msgData.dataReq.dstPanId, mCoordInfo.coordPanId, 2);           
    FLib_MemCpy(mpPacket->msgData.dataReq.srcPanId, mCoordInfo.coordPanId, 2);
    mpPacket->msgData.dataReq.dstAddrMode = mCoordInfo.coordAddrMode;
    mpPacket->msgData.dataReq.srcAddrMode = gAddrModeShort_c;
    mpPacket->msgData.dataReq.msduLength = 9;
    
    // Signal to Coordinator that a sensor message follows
    mpPacket->msgData.dataReq.pMsdu[0] = 0xFF;
    
    // Put dummy sensor data into the data packet
    mpPacket->msgData.dataReq.pMsdu[1] = dummyControlInfo;
    mpPacket->msgData.dataReq.pMsdu[2] = dummyToggleStatus;
    mpPacket->msgData.dataReq.pMsdu[3] = dummyTemperature;
    mpPacket->msgData.dataReq.pMsdu[4] = (uint8_t)dummyAccelData[0];
    mpPacket->msgData.dataReq.pMsdu[5] = (uint8_t)dummyAccelData[1];
    mpPacket->msgData.dataReq.pMsdu[6] = (uint8_t)dummyAccelData[2];
    mpPacket->msgData.dataReq.pMsdu[7] = (uint8_t)dummyPressure;
    mpPacket->msgData.dataReq.pMsdu[8] = (uint8_t)dummyBatteryLevel;

    /* Request MAC level acknowledgment of the data packet */
    mpPacket->msgData.dataReq.txOptions = gTxOptsAck_c;
    
    /* Give the data packet a handle. The handle is
    returned in the MCPS-Data Confirm message. */
    mpPacket->msgData.dataReq.msduHandle = mMsduHandle++;
#ifdef gMAC2006_d
	mpPacket->msgData.dataReq.securityLevel = 0;
#endif //gMAC2006_d	

    /* Send the Data Request to the MCPS */
    NR MSG_Send(NWK_MCPS, mpPacket);
    
    /* Prepare for another data buffer */
    mcPendingPackets++;
  }
}

/******************************************************************************
* The App_ReceiveData() function will check if it is possible to send out an
* MLME-Poll request in order to receive data from the coordinator. If its 
* permitted then a poll request is created and sent.
* 
* The function uses the coordinator information gained during the Active Scan
* for building the MLME-Poll Request message. The message is sent to the MLME
* service access point in the MAC.
*
******************************************************************************/
static void App_ReceiveData(void)
{
  /* Check if we are permitted, and if it is time to send a poll request.
  The poll interval is adjusted dynamically to the current band-width
  requirements. */
  if(mWaitPollConfirm == FALSE)
  {  
    /* This is an MLME-POLL.req command. */
    mlmeMessage_t *pMlmeMsg = MSG_AllocType(mlmeMessage_t);
    if(pMlmeMsg)
    {
      
      /* Create the Poll Request message data. */
      pMlmeMsg->msgType = gMlmePollReq_c;

      /* Use the coordinator information we got from the Active Scan. */
      memcpy(pMlmeMsg->msgData.pollReq.coordAddress, mCoordInfo.coordAddress, 8);
      memcpy(pMlmeMsg->msgData.pollReq.coordPanId, mCoordInfo.coordPanId, 2);
      pMlmeMsg->msgData.pollReq.coordAddrMode = mCoordInfo.coordAddrMode;
#ifndef gMAC2006_d	       
	  pMlmeMsg->msgData.pollReq.securityEnable = FALSE;
#else 
	  pMlmeMsg->msgData.pollReq.securityLevel = 0;
#endif //gMAC2006_d
      /* Send the Poll Request to the MLME. */
      if(MSG_Send(NWK_MLME, pMlmeMsg) == gSuccess_c)
      {
        /* Do not allow another Poll request before the confirm is received. */
        mWaitPollConfirm = TRUE;
      }
    }
  }
}


/******************************************************************************
* The App_Idle(void) function will check for network or serial terminal interface activity .
*
* The function may return either of the following values:
*   TRUE			: No activity detected
*   FALSE			: Network or serial terminal interface activity detected
*
******************************************************************************/
static bool_t App_Idle(void)
{
  if ((!MSG_Pending(&mMlmeNwkInputQueue)) &&
      (!MSG_Pending(&mMcpsNwkInputQueue)) &&
      (mWaitPollConfirm == FALSE)&&
      (TMR_AreAllTimersOff())&&
      (Comm_IsTxActive() == FALSE))
  {
    return TRUE;      
  }	 
  else
  {
    return FALSE;  
  }
}


/******************************************************************************
* The App_UpdateLEDs(uint8_t val) function will switch on/off the LEDs.
*
******************************************************************************/
static void App_UpdateLEDs(uint8_t displayMsg)
{
    if(displayMsg & LED1) Led1On(); else Led1Off();
    if(displayMsg & LED2) Led2On(); else Led2Off();
    if(displayMsg & LED3) Led3On(); else Led3Off();
    if(displayMsg & LED4) Led4On(); else Led4Off();
}


/******************************************************************************
* The App_IntervalTimeoutHandler(uint8_t timerID) function will send an event 
* to the application task after the programmed interval of time expires
*
******************************************************************************/
static void App_IntervalTimeoutHandler(uint8_t timerID)
{
   (void)timerID;
   TS_SendEvent(gAppTaskID_c, gAppEvtStartWait_c);                
}

/******************************************************************************
* The App_PollIntervalTimeoutHandler(uint8_t timerID) function will send an event 
* to the application task after the programmed interval of time expires to send
* a poll interval
******************************************************************************/
static void App_PollIntervalTimeoutHandler(uint8_t timerID)
{
   (void)timerID;
   TS_SendEvent(gAppTaskID_c, gAppEvtSendPollReq_c);                
}

/******************************************************************************
* The App_SensorIntervalTimeoutHandler(uint8_t timerID) function will send an event 
* to the application task after the programmed interval of time expires
*
******************************************************************************/
static void App_SensorIntervalTimeoutHandler(uint8_t timerID)
{
   (void)timerID;
   TS_SendEvent(gAppTaskID_c, gAppEvtSendSensorData_c);                
}

/*****************************************************************************
* Function to handle a generic key press. Called for all keys.
*****************************************************************************/
static void App_HandleGenericKey(void)
{
      if(gState == stateInit)
      {
        StopLed1Flashing();
        StopLed2Flashing();
        StopLed3Flashing();
        StopLed4Flashing();
        Led1Off();
        Led2Off();
        Led3Off();
        Led4Off();
        
        LCD_ClearDisplay();
        LCD_WriteString(1,"Application");
        LCD_WriteString(2,"    started");     
        TS_SendEvent(gAppTaskID_c, gAppEvtDummyEvent_c);        
      }
      else if(gState == stateListen)
      {
        /* Send a predefined message to Coordinator each time user presses
           a switch. */      
        #if (gLpmIncluded_d == 1) 
          
          if (flag == 0)
          {
            
            flag = 1;
            PWR_DisallowDeviceToSleep(); 
          }
          
        #endif 
        
        TS_SendEvent(gAppTaskID_c, gAppEvtSendMessage_c);
      
      } 
}

/*****************************************************************************
* The App_HandleKeys(key_event_t events) function can handle different
* key events. It waits for user to push a button in order to start 
* the application.
*
* Interface assumptions:
*     None
*
* Return value: 
*     None
*****************************************************************************/
#if (gMC1323xMatrixKBD_d == TRUE)
static void App_HandleKeys( uint8_t events, uint8_t pressedKey )   
{
 (void)events;
 (void)pressedKey;
 App_HandleGenericKey();
}
#else
static void App_HandleKeys( key_event_t events )
{
  switch ( events ) 
  { 
    case gKBD_EventSW1_c:
    case gKBD_EventSW2_c:
    case gKBD_EventSW3_c:
    case gKBD_EventSW4_c:
    case gKBD_EventLongSW1_c:
    case gKBD_EventLongSW2_c:
    case gKBD_EventLongSW3_c:
    case gKBD_EventLongSW4_c:
       App_HandleGenericKey();
      break;
    default:
      break;  
  }
}
#endif //gMC1323xMatrixKBD_d

/*****************************************************************************
* The DeepSleepWakeupStackProc(void) function is called by PWR modele each 
* time the application exits DeepSleep mode .
* 
* Return value:
*     None
*****************************************************************************/
void DeepSleepWakeupStackProc(void)
{ 
#if (gLpmIncluded_d == 1) 
  
    if (flag == 0)
    {      
      flag = 1;
      PWR_DisallowDeviceToSleep();
    }
  TS_SendEvent(gAppTaskID_c, gAppEvtDummyEvent_c);                        
#endif  
  return;
}

/******************************************************************************
* The following functions are called by the MAC to put messages into the
* Application's queue. They need to be defined even if they are not used
* in order to avoid linker errors.
*
******************************************************************************/
uint8_t MLME_NWK_SapHandler(nwkMessage_t * pMsg)
{
  /* Put the incoming MLME message in the applications input queue. */    
  MSG_Queue(&mMlmeNwkInputQueue, pMsg);
  TS_SendEvent(gAppTaskID_c, gAppEvtMessageFromMLME_c);
  return gSuccess_c;
}

uint8_t MCPS_NWK_SapHandler(mcpsToNwkMessage_t *pMsg)
{
  /* Put the incoming MCPS message in the applications input queue. */
  MSG_Queue(&mMcpsNwkInputQueue, pMsg);
  TS_SendEvent(gAppTaskID_c, gAppEvtMessageFromMCPS_c);
  return gSuccess_c;
}


uint8_t ASP_APP_SapHandler(aspToAppMsg_t *pMsg)
{
  /* If the message is not handled anywhere it must be freed. */
  MSG_Free(pMsg);
  return gSuccess_c;
}
//AQUI ESTA LA FUNCION QUE ENVIA LOS DATOS//
static void App_TransmitData(uint8_t * pData, uint8_t length)
{   
  
  mpPacket = NULL;
  
  /* Data request packet for sending serial terminal interface input to the coordinator */

  if( (mcPendingPackets < mMaxPendingDataPackets_c) && (mpPacket == NULL) )
  {
    /* If the maximum number of pending data buffes is below maximum limit 
    and we do not have a data buffer already then allocate one. */    
    mpPacket = MSG_Alloc(gMaxRxTxDataLength_c);
  }

  if(mpPacket != NULL)
  {  
    
  
    mpPacket->msgData.dataReq.pMsdu = (uint8_t*)(&(mpPacket->msgData.dataReq.pMsdu)) + sizeof(uint8_t*);
    memcpy(mpPacket->msgData.dataReq.pMsdu, (void *)pData, length); ///Esta linea es del coordinador para enviar los datos directamente del serial//
    
       
    /* Data was available in the serial terminal interface receive buffer. Now create an
    MCPS-Data Request message containing the serial terminal interface data. */
    mpPacket->msgType = gMcpsDataReq_c;
    /* Create the header using coordinator information gained during 
    the scan procedure. Also use the short address we were assigned
    by the coordinator during association. */
    
    memcpy(mpPacket->msgData.dataReq.dstAddr, mCoordInfo.coordAddress, 8);               
    memcpy(mpPacket->msgData.dataReq.srcAddr, maAddress, 2);
    memcpy(mpPacket->msgData.dataReq.dstPanId, mCoordInfo.coordPanId, 2);           
    memcpy(mpPacket->msgData.dataReq.srcPanId, mCoordInfo.coordPanId, 2);
    mpPacket->msgData.dataReq.dstAddrMode = mCoordInfo.coordAddrMode;
    mpPacket->msgData.dataReq.srcAddrMode = gAddrModeShort_c;
    mpPacket->msgData.dataReq.msduLength = mPredefinedMsgLen_c;

    /* Request MAC level acknowledgement of the data packet */
    mpPacket->msgData.dataReq.txOptions = gTxOptsAck_c;
    /* Give the data packet a handle. The handle is
    returned in the MCPS-Data Confirm message. */
    mpPacket->msgData.dataReq.msduHandle = mMsduHandle++;
#ifdef gMAC2006_d
	mpPacket->msgData.dataReq.securityLevel = 0;
#endif //gMAC2006_d	

    /* Send the Data Request to the MCPS */
    NR MSG_Send(NWK_MCPS, mpPacket);
    
    /* Prepare for another data buffer */
    mcPendingPackets++;
  }
}

